vue+xterm.js实现webssh踩坑之旅 您所在的位置:网站首页 Xterminal SSH vue+xterm.js实现webssh踩坑之旅

vue+xterm.js实现webssh踩坑之旅

2024-06-28 09:41| 来源: 网络整理| 查看: 265

最近在做的项目需要使用xterminal实现网页远程连接Linux终端,引了这个插件后发现问题很多,接下来一一记录问题所在。

一、如何在vue项目中使用xterm.js 安装xterm.js,博主使用的是3.x npm i xterm --save在项目中引用 新建组件Xterminal.vue import { Terminal } from "xterm"; import * as fit from "xterm/lib/addons/fit/fit"; import * as attach from "xterm/lib/addons/attach/attach"; import "xterm/dist/xterm.css"; Terminal.applyAddon(attach); Terminal.applyAddon(fit); export default { name: "xterminal", data() { return { term: null, terminalSocket: null, copy: '', loading: true, cols: 80, content: '' }; }, methods: { runRealTerminal(res) { this.content.operate = 'connect'; // 根据后端需求调节建立连接时发送的数据 this.terminalSocket.send( JSON.stringify(this.content) ); this.loading = false; console.log("webSocket is finished"); }, closeRealTerminal() { console.log("close"); } }, mounted() { let terminalContainer = document.getElementById("terminal"); this.term = new Terminal({ // 光标闪烁 cursorBlink: true }); this.term.open(terminalContainer, true); // open websocket this.terminalSocket = new WebSocket("ws://********"); // 填入服务器的websocket连接地址 this.terminalSocket.onopen = this.runRealTerminal; this.terminalSocket.onclose = this.closeRealTerminal; this.terminalSocket.onerror = this.errorRealTerminal; this.term.attach(this.terminalSocket); this.term._initialized = true; console.log("mounted is going on"); this.term.on("data", (data) => { console.log("data", data); this.terminalSocket.send( JSON.stringify({ operate: "command", command: data }) ); }); }, beforeDestroy() { this.terminalSocket.close(); this.term.destroy(); }, };

以上代码是我对webssh的初步实现,当代码编译通过,在浏览器上展示时,博主发现终端窗口的大小并没有占满容器。 在这里插入图片描述 在这里插入图片描述 页面布局类似于上图。主要问题有以下几点:

终端的高度无法自适应容器大小终端可显示区域未占满终端的100%宽度及高度浏览器进行缩放或放大时无法自适应

针对这些问题,最初想到的办法是过去container的宽高,在初始化terminal时对cols及rows参数进行设置,但是container的高度只在终端初始化后才会被撑开,因此获取到的高度为0。最终想到的办法是获取浏览器的innerWidth和innerHeight,计算终端容器的宽高。如上图所示,终端的高度为 window.innerHeight - 140,宽度为window.innerWidth - 230px(只是举个例子)。之后初始化时进行设置,代码如下:

const width = window.innerWidth - 230; const height = window.innerHeight - 140; this.cols = parseInt(width/9, 10); // 经过计算one col大约等同于9px this.term = new Terminal({ // 光标闪烁 cursorBlink: true, cols: this.cols, rows: parseInt(height/17, 10), // one row = 17px });

本以为到此开发结束,结果有一天心血来潮输入命令狂按a的时候,命令行过长不会换行而且把前面的内容覆盖了,淦!如下图所示。 在这里插入图片描述 百度了很多文章,却没有找到解决办法,转到github,在官方issue1359中找到了答案: 在这里插入图片描述 这只是第一种解决办法,删除term.fit()或者cols属性设置,但像他说的,这并不是一种好办法。 在这里插入图片描述 在这里插入图片描述 结合上面二者的回答原因是前后端设置的终端cols不同导致换行不正确。并且建议在设置cols后将其返回到后端,使后端设置成前端的cols。 所以博主在建立连接时,将cols也进行了传递,传递的方法很多,你可以在建立websocket连接时,将cols作为参数拼接到url后,而博主根据后端的需求将参数放在了content中进行了传递。

runRealTerminal(res) { this.content.operate = 'connect'; this.content.cols = this.cols; this.terminalSocket.send( JSON.stringify(this.content) ); this.loading = false; console.log("webSocket is finished"); },

之后确实实现了可换行的效果,但是问题又出现了,就是在浏览器缩放或放大的时候,终端内容消失了而且经常无法输入。这是因为没有使用fit()函数使其自适应。解决办法:在浏览器resize的时候调用fit函数。 在mounted钩子函数中加入:window.addEventListener('resize',this.windowChange); 在methods中定义:

windowChange(){ const width = window.innerWidth - 230; const height = window.innerHeight - 140; this.cols = parseInt(width/9, 10); this.term.fit(); this.term.resize(this.cols, parseInt(height/17, 10)); this.term.scrollToBottom(); }

同时需要向后端通过websocket发送最新的cols值。 至此,问题全部解决。end.



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有